#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h> 
#include <stdlib.h>       
#include <string.h>
#include <pthread.h>
//#include <sys/sem.h>
#include <errno.h>
#include <sys/ipc.h>
//#include <sys/msg.h>
#include <sys/timeb.h>
#include <sys/socket.h>
//#include <sys/socketvar.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <semaphore.h>
#include <string.h>
#include <termios.h>
#include <linux/input.h>
#include <semaphore.h>
#include <linux/shm.h>
#include <asm/unistd.h>
#include <sys/poll.h>

#include "../common.h"

#define recvBufSize 1024
#define sendBufSize 256
#define logBufSize 512
#define NORMAL_TO_BCD(byte) ((byte)/10*6 + (byte))


typedef enum
{
	eGetDeviceInfo	= 0x80,
	eBuzzer			= 0x81,
	eLed			= 0x82,
	eReplays		= 0x83,
	eGetDeviceTime	= 0x84,
	eSetDeviceTime	= 0x85,
	eFindCard		= 0x90,
}ProtCmdType;

typedef enum
{
	RC_SUCCESS		= 0x00,
	RC_NO_CARD		= 0xA0,
	RC_NO_COMMAND	= 0xFE,
	RC_FAILURE		= 0xFF,
}ResponseCodeType;

typedef enum
{
	eCardIdCheckSuccess		= 0,
	eCardIdCheckFail		= 1,
	eCardIdCheckNoCard		= 2,
	eCardIdCheckMax,
}CardIdCheckResultType;

typedef enum 
{
	eReplaysClosing			= 0,
	eReplaysOpening			= 1,
	eReplaysStatusMax,
}ReplaysStatusType;

typedef enum 
{
	eReplaysClose			= 0,
	eReplaysOpen			= 1,
	eReplaysActionMax,
}ReplaysActionType;

typedef enum 
{
	eActIgnore				= 0,
	eActOpenReplays			= 1,
	eActCloseReplays		= 2,
	eActBuzzerLed			= 3,
	eActTpyeMax,
}ActType;

static const char serialPortName[] = "/dev/ttyS3";
static const int baudRate = 9600;
static const int dataBit = 8;
static const char checkBit = 'N';
static const int stopBit = 1;


static const int beginNextRecvWhenLastFailTime_S = 1;
static const int TimeDelayAfterSendCommonPackage_us = 50 * 1000;
static const int TimeDelayAfterFC_us = 500 * 1000;
static const int TimeDelayAfterREPLAY_us = 500 * 1000;
static const int TimeDelayAfterOneProcess = 2 * 1000 * 1000;


static const int pollInTimeoutMs = 5000;
static const int pollOutTimeoutMs = 5000;
static const int tryToReadBytesEachTime = 32;


static const unsigned char STX = 0x02;
static const unsigned char ETX = 0x03;


static const unsigned char getDeviceInfoType	= 0x00; //0:detail info, 1:manufactory info

static const unsigned char OK_buzzer_status		= 1; 	//ring
static const unsigned char OK_buzzer_time		= 20; //OK_buzzer_time * 100ms (0~200)
static const unsigned char OK_buzzer_interal	= 1; 	//not use (1~9)

static const unsigned char FAIL_buzzer_status	= 1;
static const unsigned char FAIL_buzzer_time		= 10;
static const unsigned char FAIL_buzzer_interal	= 1;

static const unsigned char OK_led_index			= 1; 	//1~4
static const unsigned char OK_led_status		= 1; 	//0:off, 1:on, 2:toggleING
static const unsigned char OK_led_time			= 30; //OK_led_time * 100ms (0~200)
static const unsigned char OK_led_interal		= 1; 		//not use

static const unsigned char FAIL_led_index		= 1;
static const unsigned char FAIL_led_status		= 2; 
static const unsigned char FAIL_led_time		= 20; 
static const unsigned char FAIL_led_interal		= 1; 	

static const unsigned char replays_id			= 1;
static const unsigned char replays_act_set		= 1;
static const unsigned char replays_time_set		= 0;
static const unsigned char replays_act_reset	= 0;
static const unsigned char replays_time_reset	= 0;


static const char ourCardType = 'M';							//M:Mafare1, A:TypeA
static const unsigned char askCardloopTimes		= 5;

static const unsigned char maxNoCardTimes		= 2;


static int fserial = -1;
static int onlyActReplays = 1;
static CardIdCheckResultType lastResult = eCardIdCheckNoCard;
static ReplaysActionType lastReplaysAction = eReplaysClose;
static ReplaysStatusType curReplaysStatus = eReplaysClosing;
static unsigned char noCardTimes = 0;
static bool waitingReplaysReturnPackage = false;

static int checkRecvDataLegal(unsigned char *recvBuf, int realReadBytes);
static int processProtoData(const unsigned char *recvBuf, unsigned char *sendBuf);

static int getDeviceInfoReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf);
static inline int buzzerReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf);
static inline int ledReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf);
static inline int replaysReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf);
static int getDeviceTimeReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf);
static int setDeviceTimeReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf);
static int findCardReply(const unsigned char *pRealData, const unsigned char realDataSize, unsigned char *sendBuf);

static inline void FC(unsigned char *sendBuf);
static inline void BZ(unsigned char *sendBuf, CardIdCheckResultType result);
static inline void LED(unsigned char *sendBuf, CardIdCheckResultType result);
static inline void REPLAYS(unsigned char *sendBuf, CardIdCheckResultType result);

static inline void getDeviceInfo(unsigned char *sendBuf, const unsigned char type);
static inline void buzzer(unsigned char *sendBuf, const unsigned char status, const unsigned char time, const unsigned char interal);
static inline void led(unsigned char *sendBuf, const unsigned char ledIndex, const unsigned char status, const unsigned char time, const unsigned char level);
static inline void replays(unsigned char *sendBuf, const unsigned char id, const unsigned char status, const unsigned char time);
static inline void getDeviceTme(unsigned char *sendBuf);
static void setDeviceTime(unsigned char *sendBuf, const unsigned char year, const unsigned char month, const unsigned char mday, const unsigned char wday, \
							const unsigned char hour, const unsigned char minute, const unsigned char second);
static inline void findCard(unsigned char *sendBuf, const char cardType, const unsigned char loopTimes);

static void sendPackage(const unsigned char *sendBuf, const unsigned char packageSize);
static void fillPackageDataSend(unsigned char *sendBuf, const ProtCmdType cmd, const unsigned char *pData, const unsigned char dataSize, \
								const int delay_ms = TimeDelayAfterSendCommonPackage_us);
static unsigned short crc16Calc(const unsigned char *pData, const unsigned char dataSize);

static inline int setSerialPara();
static int set_opt(const int fd, const int nSpeed, const int nBits, const char nEvent, const int nStop);

static void* WorkThread(void* arg);

static void changeCardIdFromBinToString(char *str, const unsigned char *pBin, const unsigned char cardIdBytes);


int initSerialACServer()
{
	printf("into initSerialACServer\n");
#ifndef USE_AC
	//printf("initSerialACServer: not USE_AC !!\n");
	//return 0;
#endif

	//LOGD_EX("test LOGD_EX 2 !");
	//const char str[] = "LOGD_EX";
	//const int num = 6;
	//LOGD_EX("test %s ! %d gls !", str, num);

	int ret = initNetACServer();
	if (ret < 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "initSerialACServer fail ! ret = %d\n", ret);
		LOGD(logBuf);
		return -1;
	}

	fserial = open(serialPortName, O_RDWR | O_NOCTTY);
	if (fserial < 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "open serial port fail ! serialPortName=%s, fserial=%d\n", serialPortName, fserial);
		LOGD(logBuf);
		return -2;
	}

	pthread_t ptID;
	if (pthread_create(&ptID, NULL, WorkThread, (void *)0) != 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "create thread failure\n");
		LOGD(logBuf);
		return -3;
	}

	printf("initSerialACServer: USE_AC !\n");
	return 0;
}


static void* WorkThread(void* arg)
{
	setSerialPara();
		
	int ret, realReadBytes;
	unsigned char sendBuf[sendBufSize];
	unsigned char recvBuf[recvBufSize];
	struct pollfd pollflag;	
	//FC(sendBuf);
	REPLAYS(sendBuf, lastResult);

	while( !IsExit() )
	{			
		//usleep(TimeBetweenSendAndTryToRecv_S);
		pollflag.fd     = fserial;
		pollflag.events = POLLIN;
		//printf("11111111\n");
		ret = poll(&pollflag, 1, pollInTimeoutMs);
		if( ret < 0 ) 
		{
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "pollflag.revents error ! pollflag.revents = %d\n", (int)pollflag.revents);
			LOGD(logBuf);
			sleep(beginNextRecvWhenLastFailTime_S);
			FC(sendBuf);
			continue;
		}
		else if(ret == 0)
		{
			//printf("resend FC because of no reply after 5s or last reply's reply code is not success !\n");
			if (waitingReplaysReturnPackage)
			{
				REPLAYS(sendBuf, lastResult);
			}

			FC(sendBuf);
			continue;
		}
		//printf("2222222\n");
		if(!(pollflag.revents & POLLIN))
		{
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "pollflag.revents & POLLIN error ! pollflag.revents = %d\n", (int)pollflag.revents);
			LOGD(logBuf);
			sleep(beginNextRecvWhenLastFailTime_S);
			FC(sendBuf);
			continue;
		}
		//printf("3333333\n");
		realReadBytes = read(fserial, recvBuf, tryToReadBytesEachTime); 
		if(realReadBytes <= 0)
		{
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "read serial failure! realReadBytes=%d\n", realReadBytes);
			LOGD(logBuf);
			sleep(beginNextRecvWhenLastFailTime_S);
			FC(sendBuf);
			continue;
		}
		//printf("4444444\n");
		ret = checkRecvDataLegal(recvBuf, realReadBytes);
		if(ret < 0) 
		{
			sleep(beginNextRecvWhenLastFailTime_S);
			FC(sendBuf);
			continue;
		}
		//printf("5555555\n");
		ret = processProtoData(recvBuf, sendBuf);
		if(ret < 0)
		{
			sleep(beginNextRecvWhenLastFailTime_S);
			FC(sendBuf);
		}
	}
}

static int processProtoData(const unsigned char *recvBuf, unsigned char *sendBuf)
{
	ProtCmdType cmd = (ProtCmdType)recvBuf[1];
	const unsigned char *pData = &recvBuf[3];
	const unsigned char dataSize = recvBuf[2];
		
	int ret = -1;
	switch(cmd)
	{
		case eGetDeviceInfo:
			printf("get a eGetDeviceInfo reply package !\n");
			ret = getDeviceInfoReply(pData, dataSize, sendBuf);
			break;
		case eBuzzer:
			printf("get a eBuzzer reply package !\n");
			ret = buzzerReply(pData, dataSize, sendBuf);
			break;
		case eLed:
			printf("get a eLed reply package !\n");
			ret = ledReply(pData, dataSize, sendBuf);
			break;
		case eReplays:
			printf("get a eReplays reply package !\n");
			ret = replaysReply(pData, dataSize, sendBuf);
			break;
		case eGetDeviceTime:
			printf("get a eGetDeviceTime reply package !\n");
			ret = getDeviceTimeReply(pData, dataSize, sendBuf);
			break;
		case eSetDeviceTime:
			printf("get a eSetDeviceTime reply package !\n");
			ret = setDeviceTimeReply(pData, dataSize, sendBuf);
			break;
		case eFindCard:
			//printf("get a eFindCard reply package !\n");
			ret = findCardReply(pData, dataSize, sendBuf);
			break;
		default:
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "unknow cmd ! cmd=%u\n", (unsigned char)cmd);
			LOGD(logBuf);
			break;
	}
		
	return ret;
}


static int getDeviceInfoReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf)
{
	return 0;
}

static inline int buzzerReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf)
{
	printf("buzzerReply: reponseCode = %x\n", pData[0]);
	LED(sendBuf, lastResult);	
	return 0;
}

static inline int ledReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf)
{
	printf("ledReply: reponseCode = %x\n", pData[0]);
	usleep(TimeDelayAfterOneProcess);
	FC(sendBuf);
	return 0;
}

static inline int replaysReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf)
{
	waitingReplaysReturnPackage = false;

	ResponseCodeType responseCode = (ResponseCodeType)pData[0];
	if (responseCode != RC_SUCCESS)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "replaysReply:responseCode != RC_SUCCESS %u,%u\n", (unsigned char)responseCode, (unsigned char)RC_SUCCESS);
		LOGD(logBuf);
	}
	else
	{
		curReplaysStatus = ((lastReplaysAction == eReplaysOpen) ? eReplaysOpening : eReplaysClosing);
	}

	printf("curReplaysStatus = %s\n", (curReplaysStatus == eReplaysOpening) ? "opening" : "closing");
	if (!onlyActReplays)
	{
		BZ(sendBuf, lastResult);
	}
	else
	{
		onlyActReplays = 0;
		sleep(beginNextRecvWhenLastFailTime_S);
		FC(sendBuf);
	}
	
	return 0;
}

static int getDeviceTimeReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf)
{
	return 0;
}

static int setDeviceTimeReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf)
{
	return 0;
}

static int findCardReply(const unsigned char *pData, const unsigned char dataSize, unsigned char *sendBuf)
{
	CardIdCheckResultType curResult = eCardIdCheckNoCard;
	ResponseCodeType responseCode = (ResponseCodeType)pData[0];
	char cardType = (char)pData[1];
	unsigned char cardIdByteSize = pData[2];

	if(responseCode != RC_SUCCESS)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "findCardReply:responseCode != RC_SUCCESS %u,%u\n", (unsigned char)responseCode, (unsigned char)RC_SUCCESS);
		printf(logBuf);
	}
	else if(cardType != ourCardType)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "cardType not right ! cardType = %u\n", (unsigned char)cardType);
		LOGD(logBuf);
	}
	else if(3 + cardIdByteSize != dataSize)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "cardIdByteSize not right ! cardIdByteSize = %u, dataSize=%u\n", cardIdByteSize, dataSize);
		LOGD(logBuf);
	}	
	else if(cardIdByteSize * 2> MAX_CARD_NUMBER_BYTES)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "ccardIdByteSize > MAX_CARD_NUMBER_BYTES ! cardIdByteSize = %u, MAX_CARD_NUMBER_BYTES=%u\n", cardIdByteSize, MAX_CARD_NUMBER_BYTES);
		LOGD(logBuf);
	}
	else
	{
		static char cardIdStr[MAX_CARD_NUMBER_BYTES];
		changeCardIdFromBinToString(cardIdStr, &pData[3], cardIdByteSize);
		printf("get a card: %s\n", cardIdStr);

		int ret = getOneAccessCardInfo(cardIdStr, cardIdByteSize * 2);
		curResult = ret ? eCardIdCheckFail : eCardIdCheckSuccess;
	}
		
	ActType act;
	if (curReplaysStatus == eReplaysOpening)
	{
		switch (curResult)
		{
		case eCardIdCheckSuccess:
			noCardTimes = 0;
			act = eActIgnore;
			printf("eReplaysOpening ! eCardIdCheckSuccess ! reset noCardTimes ! ignore it !\n");
			break;
		case eCardIdCheckFail:
			//noCardTimes = maxNoCardTimes;
			//onlyActReplays = 0;
			//act = eActBuzzerLed;
			//break;
		case eCardIdCheckNoCard:
		default:
			noCardTimes++;
			if (noCardTimes >= maxNoCardTimes)
			{
				noCardTimes = maxNoCardTimes;
				onlyActReplays = 1;
				act = eActCloseReplays;
			}
			else
			{
				//onlyActReplays = 0;
				act = eActIgnore;
			}
			break;
		}
	}
	else
	{
		switch (curResult)
		{
		case eCardIdCheckSuccess:
			noCardTimes = 0;
			onlyActReplays = 0;
			act = eActOpenReplays;
			printf("eReplaysClosing ! eCardIdCheckSuccess ! reset noCardTimes !\n");
			break;
		case eCardIdCheckFail:
			noCardTimes = 0;
			//onlyActReplays = 0;
			act = eActBuzzerLed;
			break;
		default:
			noCardTimes = 0;
			//onlyActReplays = 1;
			act = eActIgnore;
			break;
		}
	}

	lastResult = curResult;
	switch (act)
	{
	case eActOpenReplays:
	case eActCloseReplays:
		REPLAYS(sendBuf, lastResult);
		break;
	case eActBuzzerLed:
		BZ(sendBuf, lastResult);
		break;
	default:
		break;
	}

	return 0;
}


static int checkRecvDataLegal(unsigned char *recvBuf, int realReadBytes)
{
	if(realReadBytes < 6)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "realReadBytes < 6! %d:%x %x %x %x %x %x\n", realReadBytes, recvBuf[0], recvBuf[1], recvBuf[2], recvBuf[3], recvBuf[4], recvBuf[5]);
		LOGD(logBuf);
		return -1;
	}
		
	if(recvBuf[0] != STX || recvBuf[realReadBytes - 1] != ETX)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "recvBuf[0]=%x, recvBuf[%d - 1]=%x\n", recvBuf[0], realReadBytes, recvBuf[realReadBytes - 1]);
		LOGD(logBuf);
		unsigned char i;
		for(i = 0; i < realReadBytes; i ++)
		{
			printf("%x ", recvBuf[i]);
		}
		printf("\n");
		return -2;
	}
		
	unsigned char dataSize = recvBuf[2];
	unsigned char calcDataSize = (unsigned char)(realReadBytes - 6);
	if(dataSize != calcDataSize)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "dataSize != calcDataSize %u,%u\n", dataSize,calcDataSize);
		LOGD(logBuf);
		return -3;
	}
		
	unsigned char *crcStart = &recvBuf[1];
	unsigned char crcDataSize = 2 + dataSize;
	unsigned short calcCRC = crc16Calc(crcStart, crcDataSize);
	unsigned char calcCRCHi = (calcCRC >> 0) & 0x00FF;
	unsigned char calcCRCLo = (calcCRC >> 8) & 0x00FF;
	unsigned char crcHi = recvBuf[3 + dataSize];
	unsigned char crcLo = recvBuf[4 + dataSize];
	if(calcCRCHi != crcHi || calcCRCLo != crcLo)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "calcCRCHi != crcHi || calcCRCLo != crcLo %x,%x,%x,%x\n", calcCRCHi, crcHi, calcCRCLo, crcLo);
		LOGD(logBuf);
		return -4;
	}
		
	return 0;
}


static inline void FC(unsigned char *sendBuf)
{
	//printf("into FC !\n");
	//sleep(dealySecondFC);
	//return;
	findCard(sendBuf, ourCardType, askCardloopTimes);
	//printf("out of FC !\n");
}

static inline void BZ(unsigned char *sendBuf, CardIdCheckResultType result)
{
	if(result == eCardIdCheckSuccess)
	{
		buzzer(sendBuf, OK_buzzer_status, OK_buzzer_time, OK_buzzer_interal);
	}
	else
	{
		buzzer(sendBuf, FAIL_buzzer_status, FAIL_buzzer_time, FAIL_buzzer_interal);
	}
}

static inline void LED(unsigned char *sendBuf, CardIdCheckResultType result)
{
	if (result == eCardIdCheckSuccess)
	{
		led(sendBuf, OK_led_index, OK_led_status, OK_led_time, OK_led_interal);
	}
	else
	{
		led(sendBuf, FAIL_led_index, FAIL_led_status, FAIL_led_time, FAIL_led_interal);
	}
}

static inline void closeReplays(unsigned char *sendBuf)
{
	REPLAYS(sendBuf, eCardIdCheckFail);
}

static inline void REPLAYS(unsigned char *sendBuf, CardIdCheckResultType result)
{
	if (result == eCardIdCheckSuccess)
	{
		replays(sendBuf, replays_id, replays_act_set, replays_time_set);
		lastReplaysAction = eReplaysOpen;
	}
	else
	{
		replays(sendBuf, replays_id, replays_act_reset, replays_time_reset);
		lastReplaysAction = eReplaysClose;
	}
}

static inline void getDeviceInfo(unsigned char *sendBuf, const unsigned char type)
{
	unsigned char rDataBuf[1];
	rDataBuf[0] = type;
	fillPackageDataSend(sendBuf, eGetDeviceInfo, rDataBuf, 1);
}

static inline void buzzer(unsigned char *sendBuf, const unsigned char status, const unsigned char time, const unsigned char interal)
{
	unsigned char rDataBuf[3];
	rDataBuf[0] = status;
	rDataBuf[1] = time;
	rDataBuf[2] = interal;
	fillPackageDataSend(sendBuf, eBuzzer, rDataBuf, 3);
}

static inline void led(unsigned char *sendBuf, const unsigned char ledIndex, const unsigned char status, const unsigned char time, const unsigned char level)
{
	unsigned char rDataBuf[4];
	rDataBuf[0] = ledIndex;
	rDataBuf[1] = status;
	rDataBuf[2] = time;
	rDataBuf[3] = level;
	fillPackageDataSend(sendBuf, eLed, rDataBuf, 4);
}

static inline void replays(unsigned char *sendBuf, const unsigned char id, const unsigned char status, const unsigned char time)
{
	unsigned char rDataBuf[3];
	rDataBuf[0] = id;
	rDataBuf[1] = status;
	rDataBuf[2] = time;
	fillPackageDataSend(sendBuf, eReplays, rDataBuf, 3, TimeDelayAfterREPLAY_us);	

	waitingReplaysReturnPackage = true;
}

static inline void getDeviceTme(unsigned char *sendBuf)
{
	fillPackageDataSend(sendBuf, eGetDeviceTime, NULL, 0);	
}

static void setDeviceTime(unsigned char *sendBuf, const unsigned char year, const unsigned char month, const unsigned char mday, const unsigned char wday, \
		const unsigned char hour, const unsigned char minute, const unsigned char second)
{
	if (year < 2000 || year > 2099 || month == 0 || month > 12 || mday == 0 || mday > 31 || wday > 6 || hour >= 24 || minute >= 60 || second >= 60)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "setDeviceTime param error ! %u,%u,%u,%u,%u,%u,%u\n", year, month, mday, wday, hour, minute, second);
		LOGD(logBuf);
		return;
	}

	unsigned char fixYear = (unsigned char)((year - 2000) & 0x00FF);
	unsigned char rDataBuf[7];
	rDataBuf[0] = NORMAL_TO_BCD(fixYear);
	rDataBuf[1] = NORMAL_TO_BCD(month);
	rDataBuf[2] = NORMAL_TO_BCD(mday);
	rDataBuf[3] = NORMAL_TO_BCD(wday);
	rDataBuf[4] = NORMAL_TO_BCD(hour);
	rDataBuf[5] = NORMAL_TO_BCD(minute);
	rDataBuf[6] = NORMAL_TO_BCD(second);
	fillPackageDataSend(sendBuf, eSetDeviceTime, rDataBuf, 7);
}


static inline void findCard(unsigned char *sendBuf, const char cardType, const unsigned char loopTimes)
{
	unsigned char rDataBuf[2];
	rDataBuf[0] = (unsigned char)cardType;
	rDataBuf[1] = loopTimes;
	fillPackageDataSend(sendBuf, eFindCard, rDataBuf, 2, TimeDelayAfterFC_us);
}


static void fillPackageDataSend(unsigned char *sendBuf, const ProtCmdType cmd, const unsigned char *pData, const unsigned char dataSize, const int delay_ms)
{
	sendBuf[0] = STX;
	sendBuf[1] = (unsigned char)cmd;
	sendBuf[2] = dataSize;
	if(pData && dataSize > 0)	memcpy(&sendBuf[3], pData, dataSize);
	unsigned char *crcStart = &sendBuf[1];
	unsigned char crcDataSize = 2 + dataSize;
	unsigned short crc = crc16Calc(crcStart, crcDataSize);
	sendBuf[3 + dataSize] = (crc >> 0) & 0x00FF;
	sendBuf[4 + dataSize] = (crc >> 8) & 0x00FF;
	//sendBuf[3 + dataSize] = 0x17;
	//sendBuf[4 + dataSize] = 0x8D;
	sendBuf[5 + dataSize] = ETX;
	unsigned char packageSize = 6 + dataSize;
	sendPackage(sendBuf, packageSize);
	/*printf("\nserial send package data: \n");
	for(unsigned char i = 0; i < packageSize; i ++)
	{
			printf("%x ", sendBuf[i]);
	}
	printf("\n\n");*/

	usleep(delay_ms);
}

static void sendPackage(const unsigned char *sendBuf, const unsigned char packageSize)
{
	/*if(fserial < 0)
	{
		fserial = open(serialPortName, O_RDWR|O_NOCTTY);
		if(fserial < 0)
		{   		
			char logBuf[logBufSize];
			snprintf(logBuf, logBufSize, "open serial port fail ! serialPortName=%s, fserial=%d\n", serialPortName,fserial);
			LOGD(logBuf);
			return;
		} 	
	}
		
	setSerialPara();*/

	int ret;
	struct pollfd pollflag;	
	while( !IsExit() )
	{
		pollflag.fd     = fserial;
		pollflag.events = POLLOUT;

		ret = poll(&pollflag, 1, pollOutTimeoutMs);
		if( ret <= 0 ) continue;
						
		write(fserial, sendBuf, packageSize);
		break;
	}
}


static inline int setSerialPara()
{
	return set_opt(fserial, baudRate, dataBit, checkBit, stopBit);
}

static int set_opt(const int fd, const int nSpeed, const int nBits, const char nEvent, const int nStop)
{
    struct termios newtio,oldtio;
    if  ( tcgetattr( fd,&oldtio)  !=  0) 
    { 
        //perror("SetupSerial 1");
        return -1;
    }
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD; 
    newtio.c_cflag &= ~CSIZE; 

    switch( nBits )
    {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    }

    switch( nEvent )
    {
    case 'O':                     //
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= (INPCK | ISTRIP);
        break;
    case 'E':                     //
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        break;
    case 'N':                    //
        newtio.c_cflag &= ~PARENB;
        break;
    }

switch( nSpeed )
    {
    case 1200:
        cfsetispeed(&newtio, B1200);
        cfsetospeed(&newtio, B1200);  
        break;
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 14400:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 19200:
        cfsetispeed(&newtio, B19200);
        cfsetospeed(&newtio, B19200);
        break;
    case 38400:
        cfsetispeed(&newtio, B38400);
        cfsetospeed(&newtio, B38400);
        break;
    case 57600:
        cfsetispeed(&newtio, B57600);
        cfsetospeed(&newtio, B57600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
    if( nStop == 1 )
    {
        newtio.c_cflag &=  ~CSTOPB;
    }
    else if ( nStop == 2 )
    {
        newtio.c_cflag |=  CSTOPB;
    }
    newtio.c_cc[VTIME]  = 0;
    newtio.c_cc[VMIN] = 0;	
    tcflush(fd,TCIFLUSH);
    if((tcsetattr(fd,TCSANOW,&newtio))!=0)
    {
        //perror("com set error");
        return -2;
    }
    //printf("set done!\n");
    return 0;
}


static const unsigned char aucCRCHi[] = 
{
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40
};

static const unsigned char aucCRCLo[] = 
{
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
	0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
    0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
    0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
    0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
    0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
    0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
    0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
    0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
    0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
    0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
    0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
    0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
    0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
    0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
    0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
    0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
    0x41, 0x81, 0x80, 0x40
};

/*static unsigned short crc16Calc(const unsigned char *pData, const unsigned char dataSize)
{
    unsigned char chCRCHi = 0xFF;
    unsigned char chCRCLo = 0xFF;
    unsigned short wIndex;            
    unsigned char i;
    for(i = 0; i < dataSize; i ++)
    {
		wIndex = chCRCLo ^ pData[i];
		chCRCLo = chCRCHi ^ crcTableHi[wIndex];
		chCRCHi = crcTableLo[wIndex];
    }
    
    return ((chCRCHi << 8) | chCRCLo); 
}*/


static unsigned short crc16Calc(const unsigned char *pucFrame, const unsigned char  usLen)
{
    unsigned char ucCRCHi = 0x00;
    unsigned char ucCRCLo = 0x00;
    int iIndex;
    unsigned char i;
    for(i = 0 ; i < usLen; i ++)
    {
        iIndex = ucCRCLo ^ *( pucFrame++ );
        ucCRCLo = ( unsigned char )( ucCRCHi ^ aucCRCHi[iIndex] );
        ucCRCHi = aucCRCLo[iIndex];
    }

    return (unsigned short)( ucCRCHi << 8 | ucCRCLo );
}

static void changeCardIdFromBinToString(char *str, const unsigned char *pBin, const unsigned char cardIdBytes)
{
	if (!str || !pBin || cardIdBytes == 0)
	{
		char logBuf[logBufSize];
		snprintf(logBuf, logBufSize, "changeCardIdFromBinToString param error !\n");
		LOGD(logBuf);
		return;
	}

	unsigned char i;
	for (i = 0; i < cardIdBytes; i++)
	{
		sprintf(&str[i * 2], "%x", pBin[i]);
	}
	str[cardIdBytes * 2] = '\0';
}


